package com.discovery.configurer;

import com.discovery.common.ret.RetCode;
import com.discovery.common.ret.RetResult;
import com.discovery.common.ret.ServiceException;
import com.discovery.core.annotation.json.JackJsonHttpMessageConverterEx;
import com.discovery.core.annotation.json.JsonFilterHandler;
import com.discovery.interceptor.SessionInterceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @Author xuebinlu
 * @Date 2018/5/9 15:39
 * @Version 1.0
 * @Description springmvc 该配置类
 **/
@Configuration
@Slf4j
public class NewWebMvcConfigurationSupport extends WebMvcConfigurationSupport {

    @Autowired
    private SessionInterceptor sessionInterceptor;

    @Autowired
    private JsonFilterHandler jsonFilterHandler;

    @Autowired
    JackJsonHttpMessageConverterEx jackJsonHttpMessageConverterEx;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }

    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    /**
     * 扩展添加自定义的信息转换类，该方法不会覆盖默认信息转换类
     *
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.extendMessageConverters(converters);
        converters.add(0, jackJsonHttpMessageConverterEx);
    }

    @Override
    protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        returnValueHandlers.add(jsonFilterHandler);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(sessionInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
    }


//    替代使用 @ControllerAdvice 和 @ExceptionHandler来处理。
//    @Override
//    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
//        exceptionResolvers.add(getHandlerExceptionResolver());
//    }


    /**
     * 创建异常处理
     */
    private HandlerExceptionResolver getHandlerExceptionResolver() {
        HandlerExceptionResolver handlerExceptionResolver = (request, response, handler, e) -> {
            RetResult<Object> result = getResuleByHeandleException(request, handler, e);
            responseResult(response, result);
            return new ModelAndView();
        };
        return handlerExceptionResolver;
    }

    /**
     * 根据异常类型确定返回数据
     */
    private RetResult<Object> getResuleByHeandleException(HttpServletRequest request, Object handler, Exception e) {
        RetResult<Object> result = new RetResult<>();
        if (e instanceof ServiceException) {
            result.setCode(RetCode.FAIL.getCode()).setMsg(e.getMessage()).setData(null);
            return result;
        }
        if (e instanceof NoHandlerFoundException) {
            result.setCode(RetCode.NOT_FOUND.getCode()).setMsg("接口 [" + request.getRequestURI() + "] 不存在");
            return result;
        }
        result.setCode(RetCode.INTERNAL_SERVER_ERROR.getCode()).setMsg("接口 [" + request.getRequestURI() + "] 内部错误，请联系管理员");
        String message;
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            message = String.format("接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s", request.getRequestURI(),
                    handlerMethod.getBean().getClass().getName(), handlerMethod.getMethod().getName(), e.getMessage());
        } else {
            message = e.getMessage();
        }
        log.error(message, e);
        return result;
    }

    /**
     * @Title: responseResult
     * @Description: 响应结果
     */
    private void responseResult(HttpServletResponse response, RetResult<Object> result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            ObjectMapper mapper = new ObjectMapper();
            response.getWriter().write(mapper.writeValueAsString(result));
        } catch (IOException ex) {
            log.error(ex.getMessage());
        }
    }

}
